package main

import (
	"bufio"
	"bytes"
	"crypto/rand"
	"flag"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"strings"
	"syscall"
)

var lineLimit = flag.Int("limit", 300, "每行允许的最大字符数")
var server = flag.String("server", "localhost", "服务器地址")

func appendListTxt(fn, tmp string) {
	fp, err := os.OpenFile(path.Join(tmp, "list.txt"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return
	}
	defer fp.Close()
	fp.WriteString(fmt.Sprintf("file '%s'\n", fn))
	fmt.Println(fn)
}

func text2wavefiles(text, tmp string) error {
	line1 := text

	if len(line1) == 0 {
		return nil
	}

	line1 = strings.TrimSpace(line1)

	runes1 := bytes.Runes([]byte(line1))

	//fmt.Println(string(runes1))

	if len(runes1) <= *lineLimit {
		data, err := getPCM(line1)
		if err == nil {
			fp, err := os.Create(path.Join(tmp, "tmp.wav"))
			if err != nil {
				return err
			}
			fp.Write(data)
			fp.Close()
		} else {
			return err
		}

		return nil
	}
	//length > lineLimit
	var idx = 1
	for {
		pos := getBreakPos(runes1)
		if pos > 0 {
			data, err := getPCM(string(runes1[0:pos]))
			if err != nil {
				return err
			}
			name := path.Join(tmp, fmt.Sprintf("%v-a.wav", idx))
			fp, err := os.Create(name)
			if err != nil {
				return err
			}
			fp.Write(data)
			fp.Close()
			appendListTxt(fmt.Sprintf("%v-a.wav", idx), tmp)
			idx++
		}
		if len(runes1) > pos {
			runes1 = runes1[pos:]
		} else {
			break
		}
	}

	return nil
}

func getBreakPos(data []rune) (pos int) {
	var ends1 = []byte("。！？?!;；:：,，. 、")
	runes1 := bytes.Runes(ends1)
	pos = 0
	if len(data) <= *lineLimit {
		pos = len(data)
		return
	}
	var posRec int
	for {
		if pos < *lineLimit && pos < len(data) {
			for _, r := range runes1 {
				if r == data[pos] {
					//fmt.Println("return", pos)
					posRec = pos
					break
				}
			}
		} else {
			if posRec > 0 {
				pos = posRec + 1
			}
			return
		}

		pos++

		if pos >= len(data) {
			break
		}
	}
	pos++
	return
}

func getPCM(text string) (data []byte, err error) {
	fmt.Println(text)
	url1 := fmt.Sprintf("http://%v:5000/api/tts", *server)
	body1 := strings.NewReader("text=" + url.QueryEscape(text))
	req, err := http.Post(url1, "application/x-www-form-urlencoded", body1)
	if err != nil {
		return nil, err
	}
	defer req.Body.Close()
	buf := bytes.NewBufferString("")
	n, err := io.Copy(buf, req.Body)
	data = buf.Bytes()
	fmt.Printf("file-size:%v\n", n)
	return
}

func getTmpName() string {
	var vc [2]byte
	rand.Read(vc[:])
	return fmt.Sprintf("%x", vc)
}

func main() {
	var input = flag.String("f", "", "输入文件（默认从标准输入读取）")
	flag.Parse()
	var output = flag.Arg(0)
	if output == "" {
		panic("必须指定输出文件名")
	}

	var text string
	reader := bufio.NewReader(os.Stdin)
	if *input != "" {
		fp, err := os.Open(*input)
		if err != nil {
			panic(err)
		}
		defer fp.Close()
		reader = bufio.NewReader(fp)
	}
	//go wait_sig()
	for {
		line, _, err := reader.ReadLine()
		if err != nil {
			break
		}
		text = text + string(line) + "。"
	}
	tmp := getTmpName()
	fmt.Println(tmp)
	os.MkdirAll(tmp, os.ModePerm)
	defer os.RemoveAll(tmp)
	err := text2wavefiles(text, tmp)
	if err != nil {
		panic(err)
	}
	listfile := path.Join(tmp, "list.txt")
	tmpfile := path.Join(tmp, "tmp.wav")
	_, err = os.Stat(listfile)
	if err == nil {
		fmt.Println("concat")
		cmd := exec.Command("ffmpeg", "-f", "concat", "-i", listfile, "-acodec", "pcm_s16le", "-y", tmpfile)
		err = cmd.Run()
		if err != nil {
			panic(err)
		}
		cmd = exec.Command("mv", tmpfile, output)
		cmd.Run()
		if err != nil {
			panic(err)
		}
		os.Remove(listfile)
	} else {
		cmd := exec.Command("ffmpeg", "-i", tmpfile, "-f", "wav", "-acodec", "pcm_s16le", "-y", output)
		err = cmd.Run()
		if err != nil {
			panic(err)
		}
		os.Remove(tmpfile)
	}

}

func wait_sig() {
	var c chan os.Signal = make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGABRT, syscall.SIGQUIT)
	<-c
	os.Stdin.Close()
}
